1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package com.sun.media.sound;
26
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.List;
31
32 import javax.sound.sampled.AudioFormat;
33 import javax.sound.sampled.AudioSystem;
34 import javax.sound.sampled.BooleanControl;
35 import javax.sound.sampled.Control;
36 import javax.sound.sampled.DataLine;
37 import javax.sound.sampled.FloatControl;
38 import javax.sound.sampled.LineEvent;
39 import javax.sound.sampled.LineListener;
40 import javax.sound.sampled.Control.Type;
41
42
43
44
45
46
47 public abstract class SoftMixingDataLine implements DataLine {
48
49 public static final FloatControl.Type CHORUS_SEND = new FloatControl.Type(
50 "Chorus Send") {
51 };
52
53 protected static class AudioFloatInputStreamResampler extends
54 AudioFloatInputStream {
55
56 private AudioFloatInputStream ais;
57
58 private AudioFormat targetFormat;
59
60 private float[] skipbuffer;
61
62 private SoftAbstractResampler resampler;
63
64 private float[] pitch = new float[1];
65
66 private float[] ibuffer2;
67
68 private float[][] ibuffer;
69
70 private float ibuffer_index = 0;
71
72 private int ibuffer_len = 0;
73
74 private int nrofchannels = 0;
75
76 private float[][] cbuffer;
77
78 private int buffer_len = 512;
79
80 private int pad;
81
82 private int pad2;
83
84 private float[] ix = new float[1];
85
86 private int[] ox = new int[1];
87
88 private float[][] mark_ibuffer = null;
89
90 private float mark_ibuffer_index = 0;
91
92 private int mark_ibuffer_len = 0;
93
94 public AudioFloatInputStreamResampler(AudioFloatInputStream ais,
95 AudioFormat format) {
96 this.ais = ais;
97 AudioFormat sourceFormat = ais.getFormat();
98 targetFormat = new AudioFormat(sourceFormat.getEncoding(), format
99 .getSampleRate(), sourceFormat.getSampleSizeInBits(),
100 sourceFormat.getChannels(), sourceFormat.getFrameSize(),
101 format.getSampleRate(), sourceFormat.isBigEndian());
102 nrofchannels = targetFormat.getChannels();
103 Object interpolation = format.getProperty("interpolation");
104 if (interpolation != null && (interpolation instanceof String)) {
105 String resamplerType = (String) interpolation;
106 if (resamplerType.equalsIgnoreCase("point"))
107 this.resampler = new SoftPointResampler();
108 if (resamplerType.equalsIgnoreCase("linear"))
109 this.resampler = new SoftLinearResampler2();
110 if (resamplerType.equalsIgnoreCase("linear1"))
111 this.resampler = new SoftLinearResampler();
112 if (resamplerType.equalsIgnoreCase("linear2"))
113 this.resampler = new SoftLinearResampler2();
114 if (resamplerType.equalsIgnoreCase("cubic"))
115 this.resampler = new SoftCubicResampler();
116 if (resamplerType.equalsIgnoreCase("lanczos"))
117 this.resampler = new SoftLanczosResampler();
118 if (resamplerType.equalsIgnoreCase("sinc"))
119 this.resampler = new SoftSincResampler();
120 }
121 if (resampler == null)
122 resampler = new SoftLinearResampler2();
123
124 pitch[0] = sourceFormat.getSampleRate() / format.getSampleRate();
125 pad = resampler.getPadding();
126 pad2 = pad * 2;
127 ibuffer = new float[nrofchannels][buffer_len + pad2];
128 ibuffer2 = new float[nrofchannels * buffer_len];
129 ibuffer_index = buffer_len + pad;
130 ibuffer_len = buffer_len;
131 }
132
133 public int available() throws IOException {
134 return 0;
135 }
136
137 public void close() throws IOException {
138 ais.close();
139 }
140
141 public AudioFormat getFormat() {
142 return targetFormat;
143 }
144
145 public long getFrameLength() {
146 return AudioSystem.NOT_SPECIFIED;
147 }
148
149 public void mark(int readlimit) {
150 ais.mark((int) (readlimit * pitch[0]));
151 mark_ibuffer_index = ibuffer_index;
152 mark_ibuffer_len = ibuffer_len;
153 if (mark_ibuffer == null) {
154 mark_ibuffer = new float[ibuffer.length][ibuffer[0].length];
155 }
156 for (int c = 0; c < ibuffer.length; c++) {
157 float[] from = ibuffer[c];
158 float[] to = mark_ibuffer[c];
159 for (int i = 0; i < to.length; i++) {
160 to[i] = from[i];
161 }
162 }
163 }
164
165 public boolean markSupported() {
166 return ais.markSupported();
167 }
168
169 private void readNextBuffer() throws IOException {
170
171 if (ibuffer_len == -1)
172 return;
173
174 for (int c = 0; c < nrofchannels; c++) {
175 float[] buff = ibuffer[c];
176 int buffer_len_pad = ibuffer_len + pad2;
177 for (int i = ibuffer_len, ix = 0; i < buffer_len_pad; i++, ix++) {
178 buff[ix] = buff[i];
179 }
180 }
181
182 ibuffer_index -= (ibuffer_len);
183
184 ibuffer_len = ais.read(ibuffer2);
185 if (ibuffer_len >= 0) {
186 while (ibuffer_len < ibuffer2.length) {
187 int ret = ais.read(ibuffer2, ibuffer_len, ibuffer2.length
188 - ibuffer_len);
189 if (ret == -1)
190 break;
191 ibuffer_len += ret;
192 }
193 Arrays.fill(ibuffer2, ibuffer_len, ibuffer2.length, 0);
194 ibuffer_len /= nrofchannels;
195 } else {
196 Arrays.fill(ibuffer2, 0, ibuffer2.length, 0);
197 }
198
199 int ibuffer2_len = ibuffer2.length;
200 for (int c = 0; c < nrofchannels; c++) {
201 float[] buff = ibuffer[c];
202 for (int i = c, ix = pad2; i < ibuffer2_len; i += nrofchannels, ix++) {
203 buff[ix] = ibuffer2[i];
204 }
205 }
206
207 }
208
209 public int read(float[] b, int off, int len) throws IOException {
210
211 if (cbuffer == null || cbuffer[0].length < len / nrofchannels) {
212 cbuffer = new float[nrofchannels][len / nrofchannels];
213 }
214 if (ibuffer_len == -1)
215 return -1;
216 if (len < 0)
217 return 0;
218 int remain = len / nrofchannels;
219 int destPos = 0;
220 int in_end = ibuffer_len;
221 while (remain > 0) {
222 if (ibuffer_len >= 0) {
223 if (ibuffer_index >= (ibuffer_len + pad))
224 readNextBuffer();
225 in_end = ibuffer_len + pad;
226 }
227
228 if (ibuffer_len < 0) {
229 in_end = pad2;
230 if (ibuffer_index >= in_end)
231 break;
232 }
233
234 if (ibuffer_index < 0)
235 break;
236 int preDestPos = destPos;
237 for (int c = 0; c < nrofchannels; c++) {
238 ix[0] = ibuffer_index;
239 ox[0] = destPos;
240 float[] buff = ibuffer[c];
241 resampler.interpolate(buff, ix, in_end, pitch, 0,
242 cbuffer[c], ox, len / nrofchannels);
243 }
244 ibuffer_index = ix[0];
245 destPos = ox[0];
246 remain -= destPos - preDestPos;
247 }
248 for (int c = 0; c < nrofchannels; c++) {
249 int ix = 0;
250 float[] buff = cbuffer[c];
251 for (int i = c; i < b.length; i += nrofchannels) {
252 b[i] = buff[ix++];
253 }
254 }
255 return len - remain * nrofchannels;
256 }
257
258 public void reset() throws IOException {
259 ais.reset();
260 if (mark_ibuffer == null)
261 return;
262 ibuffer_index = mark_ibuffer_index;
263 ibuffer_len = mark_ibuffer_len;
264 for (int c = 0; c < ibuffer.length; c++) {
265 float[] from = mark_ibuffer[c];
266 float[] to = ibuffer[c];
267 for (int i = 0; i < to.length; i++) {
268 to[i] = from[i];
269 }
270 }
271
272 }
273
274 public long skip(long len) throws IOException {
275 if (len > 0)
276 return 0;
277 if (skipbuffer == null)
278 skipbuffer = new float[1024 * targetFormat.getFrameSize()];
279 float[] l_skipbuffer = skipbuffer;
280 long remain = len;
281 while (remain > 0) {
282 int ret = read(l_skipbuffer, 0, (int) Math.min(remain,
283 skipbuffer.length));
284 if (ret < 0) {
285 if (remain == len)
286 return ret;
287 break;
288 }
289 remain -= ret;
290 }
291 return len - remain;
292
293 }
294
295 }
296
297 private class Gain extends FloatControl {
298
299 private Gain() {
300
301 super(FloatControl.Type.MASTER_GAIN, -80f, 6.0206f, 80f / 128.0f,
302 -1, 0.0f, "dB", "Minimum", "", "Maximum");
303 }
304
305 public void setValue(float newValue) {
306 super.setValue(newValue);
307 calcVolume();
308 }
309 }
310
311 private class Mute extends BooleanControl {
312
313 private Mute() {
314 super(BooleanControl.Type.MUTE, false, "True", "False");
315 }
316
317 public void setValue(boolean newValue) {
318 super.setValue(newValue);
319 calcVolume();
320 }
321 }
322
323 private class ApplyReverb extends BooleanControl {
324
325 private ApplyReverb() {
326 super(BooleanControl.Type.APPLY_REVERB, false, "True", "False");
327 }
328
329 public void setValue(boolean newValue) {
330 super.setValue(newValue);
331 calcVolume();
332 }
333
334 }
335
336 private class Balance extends FloatControl {
337
338 private Balance() {
339 super(FloatControl.Type.BALANCE, -1.0f, 1.0f, (1.0f / 128.0f), -1,
340 0.0f, "", "Left", "Center", "Right");
341 }
342
343 public void setValue(float newValue) {
344 super.setValue(newValue);
345 calcVolume();
346 }
347
348 }
349
350 private class Pan extends FloatControl {
351
352 private Pan() {
353 super(FloatControl.Type.PAN, -1.0f, 1.0f, (1.0f / 128.0f), -1,
354 0.0f, "", "Left", "Center", "Right");
355 }
356
357 public void setValue(float newValue) {
358 super.setValue(newValue);
359 balance_control.setValue(newValue);
360 }
361
362 public float getValue() {
363 return balance_control.getValue();
364 }
365
366 }
367
368 private class ReverbSend extends FloatControl {
369
370 private ReverbSend() {
371 super(FloatControl.Type.REVERB_SEND, -80f, 6.0206f, 80f / 128.0f,
372 -1, -80f, "dB", "Minimum", "", "Maximum");
373 }
374
375 public void setValue(float newValue) {
376 super.setValue(newValue);
377 balance_control.setValue(newValue);
378 }
379
380 }
381
382 private class ChorusSend extends FloatControl {
383
384 private ChorusSend() {
385 super(CHORUS_SEND, -80f, 6.0206f, 80f / 128.0f, -1, -80f, "dB",
386 "Minimum", "", "Maximum");
387 }
388
389 public void setValue(float newValue) {
390 super.setValue(newValue);
391 balance_control.setValue(newValue);
392 }
393
394 }
395
396 private Gain gain_control = new Gain();
397
398 private Mute mute_control = new Mute();
399
400 private Balance balance_control = new Balance();
401
402 private Pan pan_control = new Pan();
403
404 private ReverbSend reverbsend_control = new ReverbSend();
405
406 private ChorusSend chorussend_control = new ChorusSend();
407
408 private ApplyReverb apply_reverb = new ApplyReverb();
409
410 private Control[] controls;
411
412 protected float leftgain = 1;
413
414 protected float rightgain = 1;
415
416 protected float eff1gain = 0;
417
418 protected float eff2gain = 0;
419
420 protected List<LineListener> listeners = new ArrayList<LineListener>();
421
422 protected Object control_mutex;
423
424 protected SoftMixingMixer mixer;
425
426 protected DataLine.Info info;
427
428 protected abstract void processControlLogic();
429
430 protected abstract void processAudioLogic(SoftAudioBuffer[] buffers);
431
432 protected SoftMixingDataLine(SoftMixingMixer mixer, DataLine.Info info) {
433 this.mixer = mixer;
434 this.info = info;
435 this.control_mutex = mixer.control_mutex;
436
437 controls = new Control[] { gain_control, mute_control, balance_control,
438 pan_control, reverbsend_control, chorussend_control,
439 apply_reverb };
440 calcVolume();
441 }
442
443 protected void calcVolume() {
444 synchronized (control_mutex) {
445 double gain = Math.pow(10.0, gain_control.getValue() / 20.0);
446 if (mute_control.getValue())
447 gain = 0;
448 leftgain = (float) gain;
449 rightgain = (float) gain;
450 if (mixer.getFormat().getChannels() > 1) {
451
452 double balance = balance_control.getValue();
453 if (balance > 0)
454 leftgain *= (1 - balance);
455 else
456 rightgain *= (1 + balance);
457
458 }
459 }
460
461 eff1gain = (float) Math.pow(10.0, reverbsend_control.getValue() / 20.0);
462 eff2gain = (float) Math.pow(10.0, chorussend_control.getValue() / 20.0);
463
464 if (!apply_reverb.getValue()) {
465 eff1gain = 0;
466 }
467 }
468
469 protected void sendEvent(LineEvent event) {
470 if (listeners.size() == 0)
471 return;
472 LineListener[] listener_array = listeners
473 .toArray(new LineListener[listeners.size()]);
474 for (LineListener listener : listener_array) {
475 listener.update(event);
476 }
477 }
478
479 public void addLineListener(LineListener listener) {
480 synchronized (control_mutex) {
481 listeners.add(listener);
482 }
483 }
484
485 public void removeLineListener(LineListener listener) {
486 synchronized (control_mutex) {
487 listeners.add(listener);
488 }
489 }
490
491 public javax.sound.sampled.Line.Info getLineInfo() {
492 return info;
493 }
494
495 public Control getControl(Type control) {
496 if (control != null) {
497 for (int i = 0; i < controls.length; i++) {
498 if (controls[i].getType() == control) {
499 return controls[i];
500 }
501 }
502 }
503 throw new IllegalArgumentException("Unsupported control type : "
504 + control);
505 }
506
507 public Control[] getControls() {
508 return Arrays.copyOf(controls, controls.length);
509 }
510
511 public boolean isControlSupported(Type control) {
512 if (control != null) {
513 for (int i = 0; i < controls.length; i++) {
514 if (controls[i].getType() == control) {
515 return true;
516 }
517 }
518 }
519 return false;
520 }
521
522 }